package zx.x.modules.app.utils;

import com.qiniu.util.IOUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.ClassPathResource;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.util.*;



import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import javax.crypto.Cipher;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;



public class WxTkUtil {
    private byte [] certData;

    static {
        Security.addProvider(new BouncyCastleProvider());
        Security.setProperty("crypto.policy","unlimited");
    }
    /**
     * 调用微信退款接口
     */
    private String doRefund(String url, String data) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12"); //证书格式
        try {
            //InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("apiclient_cert.p12");
            //this.certData = IOUtils.toByteArray(certStream);

            /*ClassPathResource classPathResource = new ClassPathResource("static/apiclient_cert.p12");
            InputStream certStream = classPathResource.getInputStream();
            this.certData = IOUtils.toByteArray(certStream);
            certStream.read(this.certData);
            certStream.close();*/

            String path = "/usr/bin";//此处为自己实际路径
            String certPath = path+"/apiclient_cert.p12";
            File file = new File(certPath);
            InputStream certStream = new FileInputStream(file);
            this.certData = new byte[(int) file.length()];
            certStream.read(this.certData);
            certStream.close();

        } catch (Exception e) {
            System.out.println("进入微信退款 读取证书失败内容1=========================");
            e.printStackTrace();
        }
        ByteArrayInputStream is = new ByteArrayInputStream(this.certData);
        try {
            keyStore.load(is, WechatConfig.mch_id.toCharArray());
        } finally {
            is.close();
        }
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(
                        keyStore,
                        WechatConfig.mch_id.toCharArray())
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
        );
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        try {
            HttpPost httpost = new HttpPost(url); // 设置响应头信息
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();

                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

    /**
     * 签名字符串
     *
     * @param text          需要签名的字符串
     * @param key           密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static String sign(String text, String key, String input_charset) {
        text = text + "&key=" + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }

    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }

    /**
     * 申请退款
     *
     * @param orderId       商户订单号
     * @param refundId      商户退款单号
     * @param totalFee      订单金额
     * @param refundFee     退款金额
     * @param refundAccount 退款资金来源（默认传 "REFUND_SOURCE_UNSETTLED_FUNDS"）
     * 注: 退款金额不能大于订单金额
     */
    public Map<String, String> refund(String orderId, String refundId, String totalFee,
                                      String refundFee, String refundAccount) {

        Map<String, String> params = new HashMap<>();
        params.put("appid", WechatConfig.appid);
        params.put("mch_id", WechatConfig.mch_id);
        params.put("nonce_str", orderId);
        params.put("out_trade_no", orderId); //商户订单号和微信订单号二选一(我这里选的是商户订单号)
        params.put("out_refund_no", refundId);
        params.put("total_fee", totalFee);
        params.put("refund_fee", refundFee);
        params.put("refund_account", refundAccount);
        params.put("sign_type", "MD5");
        params.put("notify_url", WechatConfig.tkhd);
        String preStr = PayUtil.createLinkString(params);

        //签名算法
        String sign = (sign(preStr, WechatConfig.key, "utf-8")).toUpperCase();
        params.put("sign", sign);

        Map<String, String> map = new HashMap<>();
        try {
            String xml = mapToXml(params);
            System.out.println("=====================测试退款1"+xml);
            String xmlStr = doRefund("https://api.mch.weixin.qq.com/secapi/pay/refund", xml);
            System.out.println("=====================测试退款2"+xmlStr);
            map = xmlToMap(xmlStr);
            System.out.println("=====================测试退款3"+map);
            // 这里是将返回类型转换成了 map 如果要判断是否退款成功可以获取 map里面的 result_code 值，如果这个值等于 SUCCESS就代表退款成功，这里就可以写退款之后的逻辑，比如修改订单状态之类的，
//            if ("SUCCESS".equals(status)){
//                // 退款成功
//                // 这里就写逻辑，当然，如果不需要写逻辑的话，可以直接吧if else 删掉也是可以直接跑起来的
//
//            }else {
//                // 退款失败
//            }

        } catch (Exception e) {
            System.out.println("============进入失败内容"+e.getMessage());
        }
        return map;
    }

    public String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    private static String mapToXml(Map<String, String> param) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : param.entrySet()) {
            sb.append("<" + entry.getKey() + ">");
            sb.append(entry.getValue());
            sb.append("</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

    public static Map xmlToMap(String strxml) throws Exception {
        Map<String, String> map = new HashMap<>();
        if (null == strxml || "".equals(strxml)) {
            return null;
        }
        InputStream in = String2Inputstream(strxml);
        SAXReader read = new SAXReader();
        Document doc = read.read(in);
        //得到xml根元素
        Element root = doc.getRootElement();
        //遍历  得到根元素的所有子节点
        @SuppressWarnings("unchecked")
        List<Element> list = root.elements();
        for (Element element : list) {
            //装进map
            map.put(element.getName(), element.getText());
        }
        //关闭流
        in.close();
        return map;
    }
    private static InputStream String2Inputstream(String strxml) throws IOException {
        return new ByteArrayInputStream(strxml.getBytes("UTF-8"));
    }



    private static MessageDigest sMd5MessageDigest;
    private static StringBuilder sStringBuilder;

    public static String getRefundDecrypt(String reqInfoSecret, String key) {
        String result = "";
        try {
            Security.addProvider(new BouncyCastleProvider());
            sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
            byte[] bt = decoder.decodeBuffer(reqInfoSecret);
            String b = new String(bt);
            String md5key = md5(key).toLowerCase();

            //System.out.println(md5key);

            SecretKey secretKey = new SecretKeySpec(md5key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] resultbt = cipher.doFinal(bt);
            result = new String(resultbt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) {
        String A = "cbRfjwOKrLQCOjAU0v1Ac6cDJQhK6349ngVplZHLe010obV59BJ75z05eUzG+Um3Zk9WxNO6jtk60bBDkMLmf4dZk41wSbyx/GiNNcRp3g0GdUMjGjhlyJgMAKiLbmVwcPEQnOoikcCbwGd0VmOdWcTk67kDlE4ssYW6pgBXp5bSBVotuar2Wxi0z20HGgsz7dcIVELP9+JfGwuiVV9xkhO8sPbEO4SIO2qhkRQ0QzbDYgn9gU1Iprzv6wGxFh+Bm/lJWuiBGwhFCT2fq1xEF1nDPEyW3LOWq4daCegXpvTXoXLZp9Xp6zcdxiDCsLgj8yj+q7ZNmVNt1vTUR94ZQAI1UAtCqK+1dI89DZdbifU7o0fVm/9WQqjcOIo4WemUJU7WfCsyHXBVvx8lZezoQc5ZGZOqTEZJCVKV6OF5iqvlNnZJ1byPg7BfHZnmbIjdETFMIOkq3oPicshnNlVZ9g08DvesDZzG/KJzI8NBMFfXNMjSJyuemsZ/0jFJRtKDOWoCQetWox+mORa5BPrMwvibTLkPZL0okvnyrJgFwGtE4BFTdnN/+cfuUISXMTbeZv6UjRJwD9y8B+wi4wTSUC1QXjlZEkV+RgBNnJD/n13NWUK1nlrwev/RHLsgjoMSYnF0mYec8g1BCyW0POcp4iEDaRVMrjQnACyyeMncSxA+KawdoFEOqMuAITv3B0Q9iZOTpI7yqnpquWiphXMuKovJgLp4vnPqerMMthTeaQ/rfVVO/U6Z4K/heTZKT2Y0y7kQP2GS+r/N5Qvu+J0sihJ8opoZ0AJ7ktwGrzcmkIq/DCCtAfgdAT8x3rtSXA4f8pb7WqFssdGRqgzMZR1jlcz3LD5+Du+BWK5QmyCeynywd9b6s7oYdyU0aI75LrT5EBOtEHAMGi2rmwb1X2wlEd3g4gCr2l1EEA4dUTdhsqynG0w64VHWJkvJgTOdmzMPWYksLu463qcy6dN44WuNBG0aw7uEQQIUXeRhDEwCBQVmzXNLzwQ6wHv6O9j7yvkvZll3SuGw7bbsfdSdAfQkJkLCj/MHuEKUauiV0mQS/2M=";
        String key = "02a86cb980b1237eaa77fb86adf64657";
        System.out.println(A);
        System.out.println(key);
        String B = getRefundDecrypt(A, key);
        System.out.println(B);
    }

    public static String md5(String s) {
        sMd5MessageDigest.reset();
        sMd5MessageDigest.update(s.getBytes());
        byte[] digest = sMd5MessageDigest.digest();
        sStringBuilder.setLength(0);

        for (int i = 0; i < digest.length; ++i) {
            int b = digest[i] & 255;
            if (b < 16) {
                sStringBuilder.append('0');
            }

            sStringBuilder.append(Integer.toHexString(b));
        }

        return sStringBuilder.toString().toUpperCase();
    }

    static {
        try {
            sMd5MessageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException var1) {

        }

        sStringBuilder = new StringBuilder();
    }
}
